namespace Ocelot.WebSockets.Middleware
{
    using Core.DataAccess.Model;
    using Core.Framework;
    using Core.Framework.Common;
    using Dapper;
    using Microsoft.AspNetCore.Builder;
    using Quartz;
    using System;
    using System.Collections.Generic;
    using System.Net.Http;
    using System.Threading;

    public static class WebSocketsProxyMiddlewareExtensions
    {
        public static IApplicationBuilder UseWebSocketsProxyMiddleware(this IApplicationBuilder builder)
        {
            builder.UseWebSockets();
            RegistClientServicesCheckIsActive();
            return builder.UseMiddleware<WebSocketsProxyMiddleware>();
        }

        private static void RegistClientServicesCheckIsActive()
        {
            var job = new TimerJob();
            job.RegisterDisallowConcurrent<ClientServicesCheckTask>(a => a.WithIntervalInSeconds(10).RepeatForever(), a => a.Add("status", 3));

            job.RegisterDisallowConcurrent<ClientServicesCheckTask>(a => a.WithIntervalInSeconds(20).RepeatForever(), a => a.Add("status", 6));
        }

        private class ClientServicesCheckTask : ITimerJob
        {
            private readonly IDBFactory iDBFactory;
            private readonly IHttpClientFactory iHttpClientFactory;

            public ClientServicesCheckTask()
            {
                this.iDBFactory = ProviderOfServices.GetService<IDBFactory>();
                this.iHttpClientFactory = ProviderOfServices.GetService<IHttpClientFactory>();
            }

            public async void Execute(IJobExecutionContext context)
            {
                int status = context.MergedJobDataMap.GetIntValue("status");

                IEnumerable<ClientServices> clients;

                try
                {
                    using (var db = this.iDBFactory.Create())
                    {
                        clients = db.GetList<ClientServices>($"where [status] = {status}");
                    }
                }
                catch
                {
                    Thread.Sleep(2000);
                    this.Execute(context);
                    return;
                }

                foreach (var c in clients)
                {
                    bool isOk = false;

                    try
                    {
                        var client = this.iHttpClientFactory.CreateClient();
                        client.BaseAddress = new Uri($"{(c.isWss ? "https" : "http")}://{c.host}:{c.port}");

                        var response = await client.GetAsync("/heartbeat");

                        if (response.IsSuccessStatusCode)
                        {
                            isOk = true;

                            using (var db = this.iDBFactory.Create())
                            {
                                db.Execute("update [ClientServices] set [endHeartbeatTime] = @datetime, [status] = 3 where id = @id", new
                                {
                                    c.id,
                                    datetime = DateTime.UtcNow,
                                });
                            }
                        }
                    }
                    catch (Exception ex)
                    {
                        Console.WriteLine(ex.Message);
                    }
                    finally
                    {
                        if (!isOk)
                        {
                            using (var db = this.iDBFactory.Create())
                            {
                                db.Execute("update [ClientServices] set [endHeartbeatTime] = @datetime, [status] = 6 where id = @id", new
                                {
                                    c.id,
                                    datetime = DateTime.UtcNow,
                                });
                            }
                        }
                    }
                }
            }
        }

    }
}
